package com.redis.controller;

import org.redisson.api.*;
import org.redisson.api.map.event.EntryCreatedListener;
import org.redisson.api.map.event.EntryExpiredListener;
import org.redisson.api.map.event.EntryRemovedListener;
import org.redisson.api.map.event.EntryUpdatedListener;
import org.redisson.client.protocol.ScoredEntry;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/***
 * 程序接口调用方式
 * 异步执行方式
 */
@RestController
public class TestMapController {

    @Resource
    private RedissonClient redissonClient;

    @RequestMapping(value = "/map")
    public void map() throws InterruptedException {
        /**
         *  映射（Map）
         基于Redis的Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。
         同时还保持了元素的插入顺序。该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。
         在特定的场景下，映射缓存（Map）上的高度频繁的读取操作，使网络通信都被视为瓶颈时，可以使用Redisson提供的带有本地缓存功能的映射。*/
//        stringstring();
        /**Redisson的分布式的RMapCache
         Java对象在基于RMap的前提下实现了针对单个元素的淘汰机制。
         同时仍然保留了元素的插入顺序。由于RMapCache是基于RMap实现的，
         使它同时继承了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。
         Redisson提供的Spring Cache整合以及JCache正是基于这样的功能来实现的。

         目前的Redis自身并不支持散列（Hash）当中的元素淘汰，
         因此所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。
         为了保证资源的有效利用，每次运行最多清理300个过期元素。
         任务的启动时间将根据上次实际清理数量自动调整，间隔时间趋于1秒到1小时之间。
         比如该次清理时删除了300条元素，那么下次执行清理的时间将在1秒以后（最小间隔时间）。
         一旦该次清理数量少于上次清理数量，时间间隔将增加1.5倍。*/
//        mapCache();
        /** 本地缓存功能（Local Cache）
        在特定的场景下，映射（Map）上的高度频繁的读取操作，
        使网络通信都被视为瓶颈时，
        使用Redisson提供的带有本地缓存功能的分布式本地缓存映射RLocalCachedMapJava对象会是一个很好的选择。
        它同时实现了java.util.concurrent.ConcurrentMap和java.util.Map两个接口。
        本地缓存功能充分的利用了JVM的自身内存空间，对部分常用的元素实行就地缓存，
        这样的设计让读取操作的性能较分布式映射相比提高最多 45倍 。
        以下配置参数可以用来创建这个实例：*/
//        getLocalCachedMap();
        /** 映射持久化方式（缓存策略）
        Redisson供了将映射中的数据持久化到外部储存服务的功能。主要场景有一下几种：

        将Redisson的分布式映射类型作为业务和外部储存媒介之间的缓存。
        或是用来增加Redisson映射类型中数据的持久性，或是用来增加已被驱逐的数据的寿命。
        或是用来缓存数据库，Web服务或其他数据源的数据。
        Read-through策略
        通俗的讲，如果一个被请求的数据不存在于Redisson的映射中的时候，Redisson将通过预先配置好的MapLoader对象加载数据。

        Write-through（数据同步写入）策略
        在遇到映射中某条数据被更改时，Redisson会首先通过预先配置好的MapWriter对象写入到外部储存系统，然后再更新Redis内的数据。

        Write-behind（数据异步写入）策略
        对映射的数据的更改会首先写入到Redis，然后再使用异步的方式，通过MapWriter对象写入到外部储存系统。在并发环境下可以通过writeBehindThreads参数来控制写入线程的数量，已达到对外部储存系统写入并发量的控制。

        以上策略适用于所有实现了RMap、RMapCache、RLocalCachedMap和RLocalCachedMapCache接口的对象。*/
//        getLocalCachedMapCache();
       /** 映射监听器（Map Listener）
        Redisson为所有实现了RMapCache或RLocalCachedMapCache接口的对象提供了监听以下事件的监听器：

        事件 | 监听器 元素 添加 事件 |org.redisson.api.map.event.EntryCreatedListener
        元素 过期 事件 | org.redisson.api.map.event.EntryExpiredListener
        元素 删除 事件 | org.redisson.api.map.event.EntryRemovedListener
        元素 更新 事件 | org.redisson.api.map.event.EntryUpdatedListener*/
//        mapListener();
        /**LRU有界映射
        Redisson提供了基于Redis的以LRU为驱逐策略的分布式LRU有界映射对象。顾名思义，
        分布式LRU有界映射允许通过对其中元素按使用时间排序处理的方式，主动移除超过规定容量限制的元素。*/
//        mapMaxSize();
        /**        多值映射（Multimap）
        1  基于集（Set）的多值映射（Multimap）*/
//        setMultimap();
        /** 多值映射（Multimap）淘汰机制（Eviction）
          Multimap对象的淘汰机制是通过不同的接口来实现的。它们是RSetMultimapCache接口和RListMultimapCache接口，分别对应的是Set和List的Multimaps。
          所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。
         为了保证资源的有效利用，每次运行最多清理100个过期元素。任务的启动时间将根据上次实际清理数量自动调整，间隔时间趋于1秒到2小时之间。
         比如该次清理时删除了100条元素，那么下次执行清理的时间将在1秒以后（最小间隔时间）。
         一旦该次清理数量少于上次清理数量，时间间隔将增加1.5倍。*/
//        multimap();


        /**集（Set）
        基于Redis的Redisson的分布式Set结构的RSet Java对象实现了java.util.Set接口。
        通过元素的相互状态比较保证了每个元素的唯一性。
        该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。*/
//        getSet();
        /**集（Set）淘汰机制（Eviction）
          基于Redis的Redisson的分布式RSetCache Java对象在基于RSet的前提下实现了针对单个元素的淘汰机制。
          由于RSetCache是基于RSet实现的，使它还集成了java.util.Set接口。

          目前的Redis自身并不支持Set当中的元素淘汰，
          因此所有过期元素都是通过org.redisson.EvictionScheduler实例来实现定期清理的。为了保证资源的有效利用，
          每次运行最多清理100个过期元素。任务的启动时间将根据上次实际清理数量自动调整，间隔时间趋于1秒到2小时之间。
          比如该次清理时删除了100条元素，那么下次执行清理的时间将在1秒以后（最小间隔时间）。
          一旦该次清理数量少于上次清理数量，时间间隔将增加1.5倍。*/
//        getSetCache();
        /**集（Set）数据分片（Sharding）
        Set数据分片是Redis集群模式下的一个功能。Redisson提供的分布式RClusteredSet Java对象也是基于RSet实现的。在这里可以获取更多的信息。*/
//        getClusteredSet();


        /**有序集（SortedSet）
        基于Redis的Redisson的分布式RSortedSet Java对象实现了java.util.SortedSet接口。
        在保证元素唯一性的前提下，通过比较器（Comparator）接口实现了对元素的排序。*/
//        getSortedSet();


        /**计分排序集（ScoredSortedSet）
        基于Redis的Redisson的分布式RScoredSortedSet Java对象是一个可以按插入时指定的元素评分排序的集合。它同时还保证了元素的唯一性。*/
//        getScoredSortedSet();

        /**字典排序集（LexSortedSet）
        基于Redis的Redisson的分布式RLexSortedSet Java对象在实现了java.util.Set<String>接口的同时，
        将其中的所有字符串元素按照字典顺序排列。它公式还保证了字符串元素的唯一性。*/
//        getLexSortedSet();


        /**列表（List）
        基于Redis的Redisson分布式列表（List）结构的RList Java对象在实现了java.util.List接口的同时，确保了元素插入时的顺序。
        该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。*/
//        getList();

        /**队列（Queue）
        基于Redis的Redisson分布式无界队列（Queue）结构的RQueue
        Java对象实现了java.util.Queue接口。
        尽管RQueue对象无初始大小（边界）限制，
        但对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。*/
//        getQueue();
       /** 双端队列（Deque）
        基于Redis的Redisson分布式无界双端队列（Deque）结构的RDeque Java对象实现了java.util.Deque接口。
        尽管RDeque对象无初始大小（边界）限制，但对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。*/
//        getDeque();
        /**阻塞队列（Blocking Queue）
        基于Redis的Redisson分布式无界阻塞队列（Blocking Queue）
        结构的RBlockingQueue Java对象实现了java.util.concurrent.BlockingQueue接口。
        尽管RBlockingQueue对象无初始大小（边界）限制，但对象的最大容量受Redis限制，
        最大元素数量是4 294 967 295个。*/
        getBlockingQueue();

        /**有界阻塞队列（Bounded Blocking Queue）
        基于Redis的Redisson分布式有界阻塞队列（Bounded Blocking Queue）
        结构的RBoundedBlockingQueue Java对象实现了java.util.concurrent.BlockingQueue接口。
        该对象的最大容量受Redis限制，最大元素数量是4 294 967 295个。队列的初始容量（边界）必须在使用前设定好。*/
        getBoundedBlockingQueue();


        /**阻塞双端队列（Blocking Deque）
        基于Redis的Redisson分布式无界阻塞双端队列（Blocking Deque）结构的RBlockingDeque
        Java对象实现了java.util.concurrent.BlockingDeque接口。
        尽管RBlockingDeque对象无初始大小（边界）限制，但对象的最大容量受Redis限制，
        最大元素数量是4 294 967 295个。*/
        getBlockingDeque();

        /**阻塞公平队列（Blocking Fair Queue）
        基于Redis的Redisson分布式无界阻塞公平队列（Blocking Fair Queue）结构的RBlockingFairQueue
        Java对象在实现Redisson分布式无界阻塞队列（Blocking Queue）结构RBlockingQueue接口的基础上，
        解决了多个队列消息的处理者在复杂的网络环境下，
        网络延时的影响使“较远”的客户端最终收到消息数量低于“较近”的客户端的问题。
        从而解决了这种现象引发的个别处理节点过载的情况。

        以分布式无界阻塞队列为基础，采用公平获取消息的机制，
        不仅保证了poll、pollFromAny、pollLastAndOfferFirstTo和take方法获取消息的先入顺序，
        还能让队列里的消息被均匀的发布到处在复杂分布式环境中的各个处理节点里。*/

        getBlockingFairQueue();
        /**阻塞公平双端队列（Blocking Fair Deque）
        基于Redis的Redisson分布式无界阻塞公平双端队列（Blocking Fair Deque）
        结构的RBlockingFairDeque Java对象在实现Redisson分布式无界阻塞双端队列（Blocking Deque）
        结构RBlockingDeque接口的基础上，解决了多个队列消息的处理者在复杂的网络环境下，
        网络延时的影响使“较远”的客户端最终收到消息数量低于“较近”的客户端的问题。
        从而解决了这种现象引发的个别处理节点过载的情况。
        以分布式无界阻塞双端队列为基础，采用公平获取消息的机制，
        不仅保证了poll、take、pollFirst、takeFirst、pollLast和takeLast方法获取消息的先入顺序，
        还能让队列里的消息被均匀的发布到处在复杂分布式环境中的各个处理节点里。*/
        getBlockingFairDeque();



        /**延迟队列（Delayed Queue）
        基于Redis的Redisson分布式延迟队列（Delayed Queue）结构的RDelayedQueue
        Java对象在实现了RQueue接口的基础上提供了向队列按要求延迟添加项目的功能。
        该功能可以用来实现消息传送延迟按几何增长或几何衰减的发送策略。*/
        getDelayedQueue();
       /**优先队列（Priority Queue）
        基于Redis的Redisson分布式优先队列（Priority Queue）
        Java对象实现了java.util.Queue的接口。
        可以通过比较器（Comparator）接口来对元素排序。
        */
        getPriorityQueue();

        /**优先双端队列（Priority Deque）
        基于Redis的Redisson分布式优先双端队列（Priority Deque）
        Java对象实现了java.util.Deque的接口。
        可以通过比较器（Comparator）接口来对元素排序。*/

        getPriorityDeque();

        /**优先阻塞队列（Priority Blocking Queue）
        基于Redis的分布式无界优先阻塞队列（Priority Blocking Queue）
        Java对象的结构与java.util.concurrent.PriorityBlockingQueue类似。
        可以通过比较器（Comparator）接口来对元素排序。
        PriorityBlockingQueue的最大容量是4 294 967 295个元素。*/

        getPriorityBlockingQueue();

        /**优先阻塞双端队列（Priority Blocking Deque）
        基于Redis的分布式无界优先阻塞双端队列（Priority Blocking Deque）
        Java对象实现了java.util.Deque的接口。addLast、 addFirst、push方法不能再这个对里使用。
        PriorityBlockingDeque的最大容量是4 294 967 295个元素。*/
        getPriorityBlockingDeque();


        System.out.println("end");
    }

    private void getPriorityBlockingDeque() {
        //        RPriorityBlockingDeque<Integer> queue = redisson.getPriorityBlockingDeque("anyQueue");
//        queue.trySetComparator(new MyComparator()); // 指定对象比较器
//        queue.add(2);
//
//        queue.removeAsync(0);
//        queue.addAsync(5);
//
//        queue.pollFirst();
//        queue.pollLast();
//        queue.takeFirst();
//        queue.takeLast();
    }

    private void getPriorityBlockingQueue() throws InterruptedException {
//        RPriorityBlockingQueue<Integer> queue = redisson.getPriorityBlockingQueue("anyQueue");
//        queue.trySetComparator(new MyComparator()); // 指定对象比较器
//        queue.add(3);
//        queue.add(1);
//        queue.add(2);
//
//        queue.removeAsync(0);
//        queue.addAsync(5);
//
//        queue.take();
    }

    private void getPriorityDeque() {
//        RPriorityDeque<Integer> queue = redisson.getPriorityDeque("anyQueue");
//        queue.trySetComparator(new MyComparator()); // 指定对象比较器
//        queue.addLast(3);
//        queue.addFirst(1);
//        queue.add(2);
//
//        queue.removeAsync(0);
//        queue.addAsync(5);
//
//        queue.pollFirst();
//        queue.pollLast();
    }

    private void getPriorityQueue() {
//        RPriorityQueue<Integer> queue = redisson.getPriorityQueue("anyQueue");
//        queue.trySetComparator(new MyComparator()); // 指定对象比较器
//        queue.add(3);
//        queue.add(1);
//        queue.add(2);
//
//        queue.removeAsync(0);
//        queue.addAsync(5);
//
//        queue.poll();
    }

    private void getDelayedQueue() {
        RQueue<String> distinationQueue = redissonClient.getQueue("");
        RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(distinationQueue);
        // 10秒钟以后将消息发送到指定队列
        delayedQueue.offer("msg1", 10, TimeUnit.SECONDS);
        // 一分钟以后将消息发送到指定队列
        delayedQueue.offer("msg2", 1, TimeUnit.MINUTES);

        delayedQueue.destroy();
    }

    private void getBlockingFairDeque() {
//        RBlockingFairDeque deque = redisson.getBlockingFairDeque("myDeque");
//        deque.offer(new SomeObject());
//
//        SomeObject firstElement = queue.peekFirst();
//        SomeObject firstElement = queue.pollFirst();
//        SomeObject firstElement = queue.pollFirst(10, TimeUnit.MINUTES);
//        SomeObject firstElement = queue.takeFirst();
//
//        SomeObject lastElement = queue.peekLast();
//        SomeObject lastElement = queue.pollLast();
//        SomeObject lastElement = queue.pollLast(10, TimeUnit.MINUTES);
//        SomeObject lastElement = queue.takeLast();
    }

    private void getBlockingFairQueue() {
//        RBlockingFairQueue queue = redisson.getBlockingFairQueue("myQueue");
//        queue.offer(new SomeObject());
//
//        SomeObject obj = queue.peek();
//        SomeObject someObj = queue.poll();
//        SomeObject ob = queue.poll(10, TimeUnit.MINUTES);
    }

    private void getBlockingDeque() throws InterruptedException {
        RBlockingDeque<Integer> deque = redissonClient.getBlockingDeque("anyDeque");
        deque.putFirst(1);
        deque.putLast(2);
        Integer firstValue = deque.takeFirst();
        Integer lastValue = deque.takeLast();
        Integer firstValue1 = deque.pollFirst(10, TimeUnit.MINUTES);
        Integer lastValue2 = deque.pollLast(3, TimeUnit.MINUTES);
    }

    private void getBoundedBlockingQueue() throws InterruptedException {
        RBoundedBlockingQueue<String> queue = redissonClient.getBoundedBlockingQueue("anyQueue");
// 如果初始容量（边界）设定成功则返回`真（true）`，
// 如果初始容量（边界）已近存在则返回`假（false）`。
        queue.trySetCapacity(2);

        queue.offer(new String("1"));
        queue.offer(new String("1"));
// 此时容量已满，下面代码将会被阻塞，直到有空闲为止。
        queue.put(new String());

        String obj = queue.peek();
        String someObj = queue.poll();
        String ob = queue.poll(10, TimeUnit.MINUTES);
    }

    private void getBlockingQueue() throws InterruptedException {
        RBlockingQueue<String> queue = redissonClient.getBlockingQueue("anyQueue");
        queue.offer(new String());
        queue.add("");
        String obj = queue.peek();
        String someObj = queue.poll();
        String ob = queue.poll(10, TimeUnit.MINUTES);
        queue.deleteAsync();
    }

    private void getDeque() {
        RDeque<String> queue = redissonClient.getDeque("anyDeque");
        queue.addFirst(new String());
        queue.addLast(new String());
        String obj = queue.removeFirst();
        String someObj = queue.removeLast();
    }

    private void getQueue() {
        RQueue<String> queue = redissonClient.getQueue("anyQueue");
        queue.clear();
        queue.add("1");
        queue.add("2");
        queue.add("3");
        queue.add("4");
        queue.add("5");
        String s = queue.pollLastAndOfferFirstTo("2");
        List<String> list = queue.readAll();
        String obj = queue.peek();
        String someObj = queue.poll();
        System.out.println("12");
    }

    private void getList() {
        RList<String> list = redissonClient.getList("anyList");
        list.add(new String());
        list.get(0);
        list.remove(new String());
    }

    private void getLexSortedSet() {
        RLexSortedSet lexSortedSet = redissonClient.getLexSortedSet("simple");
        lexSortedSet.add("d");
        lexSortedSet.addAsync("e");
        lexSortedSet.add("f");

//        lexSortedSet.lexRangeTail("d", false);
//        lexSortedSet.lexCountHead("e");
//        lexSortedSet.lexRange("d", true, "z", false);
    }

    private void getScoredSortedSet() {
        RScoredSortedSet<String> scoredSortedSet = redissonClient.getScoredSortedSet("simple");

        scoredSortedSet.add(0.13, "1");
        scoredSortedSet.addAsync(0.251, "2");
        scoredSortedSet.add(0.302, "3");
        scoredSortedSet.add(0.304, "4");
        scoredSortedSet.add(0.304, "12");
        scoredSortedSet.add(0.305, "5");
        scoredSortedSet.add(0.306, "6");
        scoredSortedSet.add(0.307, "7");
        scoredSortedSet.add(0.308, "8");

        scoredSortedSet.pollFirst();
        scoredSortedSet.pollLast();

        int index = scoredSortedSet.rank("2"); // 获取元素在集合中的位置
        Double score = scoredSortedSet.getScore("2"); // 获取元素的评分


        Collection<ScoredEntry<String>> scoredEntries = scoredSortedSet.entryRange(0, 10);
    }

    private void getSortedSet() {
        //        RSortedSet<Integer> sortedSet = redissonClient.getSortedSet("anySet");
//        sortedSet.trySetComparator(new MyComparator()); // 配置元素比较器
//        sortedSet.add(3);
//        sortedSet.add(1);
//        sortedSet.add(2);
//
//        sortedSet.removeAsync(0);
//        sortedSet.addAsync(5);
    }

    private void getClusteredSet() {
        //        RClusteredSet<String> set = redisson.getClusteredSet("anySet");
//        set.add(new String());
//        set.remove(new String());
    }

    private void getSetCache() {
        RSetCache<String> setCache = redissonClient.getSetCache("anySet");
// ttl = 10 seconds
        setCache.add(new String("11"), 10, TimeUnit.SECONDS);
    }

    private void getSet() {
        RSet<String> set = redissonClient.getSet("anySet");
        set.add(new String());
        set.remove(new String());
    }

    private void multimap() {

//        RSetMultimapCache的使用范例：

        RSetMultimapCache<String, String> multimap = redissonClient.getSetMultimapCache("myMultimap");
        multimap.put("1", "a");
        multimap.put("1", "b");
        multimap.put("1", "c");

        multimap.put("2", "e");
        multimap.put("2", "f");

        multimap.expireKey("2", 10, TimeUnit.MINUTES);
    }

    private void setMultimap() {



        RSetMultimap<String, String> setMultimap = redissonClient.getSetMultimap("myMultimap");
        setMultimap.put(new String("0"), new String("1"));
        setMultimap.put(new String("0"), new String("2"));
        setMultimap.put(new String("3"), new String("4"));

        Set<String> allValues = setMultimap.get(new String("0"));

        List<String> newValues = Arrays.asList(
                new String("7"),
                new String("6"),
                new String("5"));


        Set<String> oldValues = setMultimap.replaceValues(new String("0"), newValues);

        Set<String> allValuess = setMultimap.get(new String("0"));


        Set<String> removedValues = setMultimap.removeAll(new String("0"));

//        基于列表（List）的多值映射（Multimap）
//        基于List的Multimap在保持插入顺序的同时允许一个字段下包含重复的元素。

        RListMultimap<String, String> listMultimap = redissonClient.getListMultimap("listMultimap");
        listMultimap.put(new String("0"), new String("1"));
        listMultimap.put(new String("0"), new String("2"));
        listMultimap.put(new String("0"), new String("1"));
        listMultimap.put(new String("3"), new String("4"));

        List<String> allValueslistMultimap = listMultimap.get(new String("0"));

        Collection<String> newValueslistMultimap = Arrays.asList(new String("7"), new String("6"), new String("5"));

        List<String> oldValueslistMultimap = listMultimap.replaceValues(new String("0"), newValues);

        List<String> removedValueslistMultimap = listMultimap.removeAll(new String("0"));
    }

    private void mapMaxSize() {


        RMapCache<String, String> mapMaxSize = redissonClient.getMapCache("map");
        // 尝试将该映射的最大容量限制设定为10
        mapMaxSize.trySetMaxSize(2);

        // 将该映射的最大容量限制设定或更改为10
        mapMaxSize.setMaxSize(2);

        mapMaxSize.put("1", "2");
        mapMaxSize.put("2", "2");
        mapMaxSize.put("3", "2");
        mapMaxSize.put("4", "4", 1, TimeUnit.SECONDS);
    }

    private void mapListener() {
        //
//
//        使用范例：

        RMapCache<String, Integer> mapListener = redissonClient.getMapCache("myMap");
// 或
//        RLocalCachedMapCache<String, Integer> map = redisson.getLocalCachedMapCache("myMap", options);

        int updateListener = mapListener.addListener((EntryUpdatedListener<String, Integer>) event -> {
            event.getKey(); // 字段名
            event.getValue(); // 新值
            event.getOldValue(); // 旧值
            // ...
        });

        int createListener = mapListener.addListener((EntryCreatedListener<Integer, Integer>) event -> {
            event.getKey(); // 字段名
            event.getValue(); // 值
            // ...
        });

        int expireListener = mapListener.addListener((EntryExpiredListener<Integer, Integer>) event -> {
            event.getKey(); // 字段名
            event.getValue(); // 值
            // ...
        });

        int removeListener = mapListener.addListener((EntryRemovedListener<Integer, Integer>) event -> {
            event.getKey(); // 字段名
            event.getValue(); // 值
            // ...
        });

        mapListener.removeListener(updateListener);
        mapListener.removeListener(createListener);
        mapListener.removeListener(expireListener);
        mapListener.removeListener(removeListener);
    }

    private void getLocalCachedMapCache() {
        //

//
//        配置范例：
//        MapOptions<K, V> options = MapOptions.<K, V>defaults()
//                .writer(myWriter)
//                .loader(myLoader);
//
//        RMap<K, V> map = redisson.getMap("test", options);
//// 或
//        RMapCache<K, V> map = redisson.getMapCache("test", options);
//// 或
//        RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
//// 或
//        RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);
//
//
    }

    private void getLocalCachedMap() {


        LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
                // 用于淘汰清除本地缓存内的元素
                // 共有以下几种选择:
                // LFU - 统计元素的使用频率，淘汰用得最少（最不常用）的。
                // LRU - 按元素使用时间排序比较，淘汰最早（最久远）的。
                // SOFT - 元素用Java的WeakReference来保存，缓存元素通过GC过程清除。
                // WEAK - 元素用Java的SoftReference来保存, 缓存元素通过GC过程清除。
                // NONE - 永不淘汰清除缓存元素。
                .evictionPolicy(LocalCachedMapOptions.EvictionPolicy.NONE)
                // 如果缓存容量值为0表示不限制本地缓存容量大小
                .cacheSize(1000)
                // 以下选项适用于断线原因造成了未收到本地缓存更新消息的情况。
                // 断线重连的策略有以下几种：
                // CLEAR - 如果断线一段时间以后则在重新建立连接以后清空本地缓存
                // LOAD - 在服务端保存一份10分钟的作废日志
                //        如果10分钟内重新建立连接，则按照作废日志内的记录清空本地缓存的元素
                //        如果断线时间超过了这个时间，则将清空本地缓存中所有的内容
                // NONE - 默认值。断线重连时不做处理。
                .reconnectionStrategy(LocalCachedMapOptions.ReconnectionStrategy.NONE)
                // 以下选项适用于不同本地缓存之间相互保持同步的情况
                // 缓存同步策略有以下几种：
                // INVALIDATE - 默认值。当本地缓存映射的某条元素发生变动时，同时驱逐所有相同本地缓存映射内的该元素
                // UPDATE - 当本地缓存映射的某条元素发生变动时，同时更新所有相同本地缓存映射内的该元素
                // NONE - 不做任何同步处理
                .syncStrategy(LocalCachedMapOptions.SyncStrategy.INVALIDATE)
                // 每个Map本地缓存里元素的有效时间，默认毫秒为单位
                .timeToLive(10000)
                // 或者
                .timeToLive(10, TimeUnit.SECONDS)
                // 每个Map本地缓存里元素的最长闲置时间，默认毫秒为单位
                .maxIdle(10000)
                // 或者
                .maxIdle(10, TimeUnit.SECONDS);


        RLocalCachedMap<String, Integer> localCachedMap = redissonClient.getLocalCachedMap("localCachedMap", options);

        Integer prevObjectlocal = localCachedMap.put("123", 1);
        Integer prevObjectlocal2 = localCachedMap.putIfAbsent("123", 2);
        Integer currentObjectlocal = localCachedMap.putIfAbsent("323", 2);
        Integer objlocal = localCachedMap.remove("123");

        // 在不需要旧值的情况下可以使用fast为前缀的类似方法
        localCachedMap.fastPut("a", 1);
        localCachedMap.fastPutIfAbsent("d", 32);
        localCachedMap.fastRemove("b");

        RFuture<Integer> putAsyncFuturelocal = localCachedMap.putAsync("321",12);
        RFuture<Boolean> fastPutAsyncFuturelocal = localCachedMap.fastPutAsync("321",33);

        localCachedMap.fastPutAsync("321", 1);
        localCachedMap.fastRemoveAsync("321");
        localCachedMap.destroy();

        localCachedMap.fastPut("c", 1);
        System.out.println("localCachedMap.destroy();");
    }

//        映射（Map）的元素淘汰（Eviction），本地缓存（LocalCache）和数据分片（Sharding）
//        Redisson提供了一系列的映射类型的数据结构，这些结构按特性主要分为三大类：
//
//        元素淘汰（Eviction） 类 -- 带有元素淘汰（Eviction）机制的映射类允许针对一个映射中每个元素单独设定 有效时间 和 最长闲置时间 。
//
//        本地缓存（LocalCache） 类 -- 本地缓存（Local Cache）也叫就近缓存（Near Cache）。这类映射的使用主要用于在特定的场景下，映射缓存（MapCache）上的高度频繁的读取操作，使网络通信都被视为瓶颈的情况。Redisson与Redis通信的同时，还将部分数据保存在本地内存里。这样的设计的好处是它能将读取速度提高最多 45倍 。
//
//        数据分片（Sharding） 类 -- 数据分片（Sharding）类仅适用于Redis集群环境下，因此带有数据分片（Sharding）功能的映射也叫集群分布式映射。它利用分库的原理，将单一一个映射结构切分为若干个小的映射，并均匀的分布在集群中的各个槽里。这样的设计能使一个单一映射结构突破Redis自身的容量限制，让其容量随集群的扩大而增长。在扩容的同时，还能够使读写性能和元素淘汰处理能力随之成线性增长。
//
//        以下列表是Redisson提供的所有映射的名称及其特性：
//


//        元素淘汰功能（Eviction）

    private void mapCache() {
        RMapCache<String, String> mapCache = redissonClient.getMapCache("mapCache");
        // 有效时间 ttl = 10分钟
        mapCache.put("key1", "key1", 30, TimeUnit.SECONDS);
        // 有效时间 ttl = 10分钟, 最长闲置时间 maxIdleTime = 10秒钟
        mapCache.put("key2", "key2", 30, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);

        // 有效时间 = 3 秒钟
        mapCache.putIfAbsent("key3", "key3", 40, TimeUnit.SECONDS);
        // 有效时间 ttl = 40秒钟, 最长闲置时间 maxIdleTime = 10秒钟
        mapCache.putIfAbsent("key4", "key4", 40, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);


        System.out.println( mapCache.get("key1"));
        System.out.println( mapCache.get("key2"));
        System.out.println( mapCache.get("key3"));
        System.out.println( mapCache.get("key4"));
    }


    private void stringstring() {

        RMap<String, String> map = redissonClient.getMap("anyMap");
        String prevObject = map.put("123", new String("qqqqqqqqqqqqqq"));
        String currentObject = map.putIfAbsent("323", new String("wwwwwwwwwww"));
        String obj = map.remove("123");

        map.fastPut("321",  new String("fastPut"));
        map.fastRemove("321");

        RFuture<String> putAsyncFuture = map.putAsync("321","rrrrrrrr");
        RFuture<Boolean> fastPutAsyncFuture = map.fastPutAsync("321","rrrrrrrr");

        map.fastPutAsync("321", new String());
        map.fastRemoveAsync("321");


//        映射的字段锁的用法：
        String k = new String();
        RLock keyLock = map.getLock(k);
        keyLock.lock();
        try {
            String v = map.get(k);
            // 其他业务逻辑
        } finally {
            keyLock.unlock();
        }

        RReadWriteLock rwLock = map.getReadWriteLock(k);
        rwLock.readLock().lock();
        try {
            String v = map.get(k);
            // 其他业务逻辑
        } finally {
            rwLock.readLock().unlock();
        }
    }

    //    如何通过加载数据的方式来降低过期淘汰事件发布信息对网络的影响
//    代码范例:
    public void loadData(String cacheName, Map<String, String> data) {
        RLocalCachedMap<Object, Object> clearMap = redissonClient.getLocalCachedMap(cacheName,
                LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(LocalCachedMapOptions.SyncStrategy.INVALIDATE));
        RLocalCachedMap<Object, Object> loadMap = redissonClient.getLocalCachedMap(cacheName,
                LocalCachedMapOptions.defaults().cacheSize(1).syncStrategy(LocalCachedMapOptions.SyncStrategy.NONE));

        loadMap.putAll(data);
        clearMap.clearLocalCache();
    }
}
